/*
 *  Copyright (c) 2022 ZhuHai Jieli Technology Co.,Ltd.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

s32 vm_open(u16 index);
VM_ERR vm_close(vm_hdl hdl);

// bt vm interface
struct rw_file_hdl {
    // OS_EVENT mutex;
    vm_hdl fhdl;
    u16 fptr;
    u16 fsize;
};
/* should the same with bt_syscfg_file in bt libs */
struct syscfg_file {
    int (*open)(int id, int fsize);
    int (*read)(void *buf, int len);
    int (*write)(void *buf, int len);
    int (*seek)(int from, int pos);   // from: 0 begin  1 curr
    int (*close)();
};

static struct rw_file_hdl  rwfile;

#define VM_FILE_SIZE  64

static int rw_cfg_file_open(int id, int fsize)
{
    rwfile.fptr = 0;
    rwfile.fsize = fsize;

    ASSERT(fsize <= VM_FILE_SIZE);

    rwfile.fhdl = vm_open(id);

    if (rwfile.fhdl) {
        return 1;
    }

    return 0;
}

static int rw_cfg_file_close(void)
{
    if (rwfile.fhdl) {
        vm_close(rwfile.fhdl);
        rwfile.fhdl = 0;
    }
    return 1;
}

static int rw_cfg_file_read(void *buf, int len)
{
    u8 data[VM_FILE_SIZE];

    if (!rwfile.fhdl) {
        return 0;
    }

    memset_s(data, VM_FILE_SIZE, 0xFF, VM_FILE_SIZE);

    ASSERT(len <= (rwfile.fsize - rwfile.fptr));

    s32 err = syscfg_read(rwfile.fhdl, data, len);

    memcpy_s(buf, len, data + rwfile.fptr, len);

    rwfile.fptr += len;

    return len;
}

static int rw_cfg_file_write(void *buf, int len)
{
    u8 *p;
    u8 data[VM_FILE_SIZE];

    if (!rwfile.fhdl) {
        return 0;
    }

    ASSERT(len <= (rwfile.fsize - rwfile.fptr));

    if (len == rwfile.fsize) {
        p = buf;
    } else {
        syscfg_read(rwfile.fhdl, data, len);

        memcpy_s(data + rwfile.fptr, len, buf, len);
        p = data;
    }

    s32 err = syscfg_write(rwfile.fhdl, p, len);

    rwfile.fptr += len;
    return len;
}

static int rw_cfg_file_seek(int from, int pos)
{
    if (from == 0) {
        rwfile.fptr = pos;
    } else {
        rwfile.fptr += pos;
    }

    return 0;
}

static const struct syscfg_file rw_file = {
    .open = rw_cfg_file_open,
    .close = rw_cfg_file_close,
    .read = rw_cfg_file_read,
    .write = rw_cfg_file_write,
    .seek = rw_cfg_file_seek,
};

void *bt_vm_interface(void)
{
    memset_s(&rwfile, sizeof(rwfile), 0, sizeof(rwfile));
    return (void *)&rw_file;
}

